package VNF_Deployment_SBA_28nodes;

import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;

import test.Posong;
import cern.colt.matrix.tdouble.DoubleFactory1D;
import cern.colt.matrix.tdouble.DoubleFactory2D;
import cern.colt.matrix.tdouble.DoubleMatrix1D;
import cern.colt.matrix.tdouble.DoubleMatrix2D;
import cern.colt.matrix.tint.IntFactory1D;
import cern.jet.math.tdouble.DoubleFunctions;


import com.net2plan.interfaces.networkDesign.Demand;
import com.net2plan.interfaces.networkDesign.Link;
import com.net2plan.interfaces.networkDesign.Net2PlanException;
import com.net2plan.interfaces.networkDesign.NetPlan;
import com.net2plan.interfaces.networkDesign.NetworkElement;
import com.net2plan.interfaces.networkDesign.NetworkLayer;
import com.net2plan.interfaces.networkDesign.Node;
import com.net2plan.interfaces.networkDesign.ProtectionSegment;
import com.net2plan.interfaces.networkDesign.Route;
import com.net2plan.interfaces.networkDesign.SharedRiskGroup;
import com.net2plan.interfaces.simulation.IEventProcessor;
import com.net2plan.interfaces.simulation.SimEvent;
import com.net2plan.libraries.WDMUtils;
import com.net2plan.utils.Constants.RoutingType;
import com.net2plan.utils.InputParameter;
import com.net2plan.utils.Pair;
import com.net2plan.utils.Quadruple;
import com.net2plan.utils.RandomUtils;
import com.net2plan.utils.Triple;

public class Test_Pro_nfv extends IEventProcessor{
	
	private double stat_trafficOfferedConnections , stat_trafficCarriedConnections;
	private double stat_trafficAttemptedToRecoverConnections , stat_trafficSuccessfullyRecoveredConnections;
	private long stat_numOfferedConnections , stat_numCarriedConnections;
	private long stat_numAttemptedToRecoverConnections , stat_numSuccessfullyRecoveredConnections;
	private double stat_transitoryInitTime;
	
	private int numberofdeployedvnf=0;
	private int mfsi=0;
	private double averagecost=0.0;
	
	public static int numberofallslot = 358;
	public static int numberofvnftype = 8;
	public static int numberofdcnodes = 14;

	
	
	private int k = 0;
	List<Double> averagecapacitylist = new ArrayList<Double>();
	private double avg = 0.0;
	

	@Override
	public String getDescription() {
		return "Implements the reactions of a WDM network carrying lightpaths in a fixed grid of wavelengths";
	}

	@Override
	public List<Triple<String, String, String>> getParameters() {
		/* Returns the parameter information for all the InputParameter objects defined in this object (uses Java reflection) */
		return InputParameter.getInformationAllInputParameterFieldsOfObject(this);
	}

	@Override
	public void initialize(NetPlan initialNetPlan, Map<String, String> algorithmParameters, Map<String, String> simulationParameters, Map<String, String> net2planParameters) {
		
		/* Initialize all InputParameter objects defined in this object (this uses Java reflection) */
		InputParameter.initializeAllInputParameterFieldsOfObject(this, algorithmParameters);
		
	}

	@Override
	public void processEvent(NetPlan currentNetPlan, SimEvent event) {
		
		System.out.println("start");
		
		
		if (event.getEventType()==200) {
			
			NetPlan VNFnetplan = (NetPlan)event.getEventObject();
			
			String ch = new String() ;
			ch = "D:\\Net2Plan-0.4.0\\workspace\\data\\networkTopologies\\US_Backbone.n2p";
			File f1 = new File(ch);
			currentNetPlan = new NetPlan(f1);
			
			int numberofsubnodes = currentNetPlan.getNumberOfNodes();
			
			List<Link> vnflinklist = VNFnetplan.getLinks(VNFnetplan.getNetworkLayerDefault());
			List<Double> linkcapacitylist = new ArrayList<Double>();
			
			for(Link link:vnflinklist) {
				linkcapacitylist.add(link.getCapacity());
			}
		
			double total=0.0;
			double average = 0.0;
			
			for(double a:linkcapacitylist) {
				total=total+a;
			}
			
			average=total/linkcapacitylist.size();
			
			averagecapacitylist.add(average);
			
			double t = 0.0;
			
			for(double b:averagecapacitylist) {
				t=t+b;
			}
			
			avg = t/averagecapacitylist.size();
			
			
			List<Node> subnodelist = currentNetPlan.getNodes();
			List<Integer> dcindexlist = new ArrayList<Integer>();
			
			for(Node node:subnodelist) {
				if(node.getAttribute("DataCenter").equals("1")) {
					dcindexlist.add(subnodelist.indexOf(node));
				}
			}
			
			System.out.println("index of dc node :");
			for(int i:dcindexlist) {
				System.out.print(i+" ");
			}
			
			System.out.println();
			
			List<LinkMappingReturn> resource = new LinkedList<LinkMappingReturn>();
			LinkMappingReturn linkmappingreturn = new LinkMappingReturn();
			NodeMappingReturn nodemappingreturn = new NodeMappingReturn();
			
			currentNetPlan = Combination10.removeLayers(currentNetPlan);
			currentNetPlan = Combination10.removeAllLayerDemand(currentNetPlan);
			nodemappingreturn = Combination10.nodeMapping(VNFnetplan,currentNetPlan);
			
			if(nodemappingreturn.isSign()) {
				
				linkmappingreturn = Combination10.linkMapping(VNFnetplan, currentNetPlan);
				
				if(linkmappingreturn.isSign()) {
					
					System.out.println("Mapping success!");
					
					
				}
				
				else {
					System.out.println("Mapping failed!");
				}
				
				numberofdeployedvnf = Combination10.numberofDeployedVNF(currentNetPlan);
				
				System.out.println("Average link capacity is "+avg);
				
				System.out.println("********************");
				
				System.out.println("number of VNF in network is "+numberofdeployedvnf);
				
				mfsi = Combination10.MFSI(currentNetPlan);
				
				System.out.println("MFSI in network is "+mfsi);
				
				
				averagecost = (mfsi*1.0/numberofallslot)+(numberofdeployedvnf*1.0/(numberofvnftype*numberofsubnodes));
				
				System.out.println("Averagecost of network is "+averagecost);
				
			}
			
			else {
				System.out.println("Mapping failed!");
			}
			
			System.out.println("------------------------------------------------------------------------------");
			
			String sh = new String() ;
			sh = "D:\\Net2Plan-0.4.0\\workspace\\data\\networkTopologies\\US_Backbone.n2p";
			File f_1= new File(sh);
			currentNetPlan.saveToFile(f_1);
			
			k++;
			
		}
		
		else throw new Net2PlanException ("Unknown event type: " + event);
		
		
	}
	
	
	@Override
	public String finish(StringBuilder output, double simTime)
	{
		final double trafficBlockingOnConnectionSetup = stat_trafficOfferedConnections == 0? 0 : 1 - (stat_trafficCarriedConnections / stat_trafficOfferedConnections );
		final double connectionBlockingOnConnectionSetup = stat_numOfferedConnections == 0? 0.0 : 1 - (((double) stat_numCarriedConnections) / ((double) stat_numOfferedConnections));
		final double successProbabilityRecovery = stat_numAttemptedToRecoverConnections == 0? 0.0 : (((double) stat_numSuccessfullyRecoveredConnections) / ((double) stat_numAttemptedToRecoverConnections));
		final double successProbabilityTrafficRecovery = stat_trafficAttemptedToRecoverConnections == 0? 0.0 : (((double) stat_trafficSuccessfullyRecoveredConnections) / ((double) stat_trafficAttemptedToRecoverConnections));
		final double dataTime = simTime - stat_transitoryInitTime;
		if (dataTime <= 0) { output.append ("<p>No time for data acquisition</p>"); return ""; }

		output.append (String.format("<p>Total traffic of offered connections: number connections %d, total time average traffic: %f</p>", stat_numOfferedConnections, stat_trafficOfferedConnections / dataTime));
		output.append (String.format("<p>Total traffic of carried connections: number connections %d, total time average traffic: %f</p>", stat_numCarriedConnections, stat_trafficCarriedConnections / dataTime));
		output.append (String.format("<p>Blocking at connection setup: Probability of blocking a connection: %f, Fraction of blocked traffic: %f</p>", connectionBlockingOnConnectionSetup , trafficBlockingOnConnectionSetup));
		output.append (String.format("<p>Number connections attempted to recover: %d (summing time average traffic: %f). </p>", stat_numAttemptedToRecoverConnections, stat_trafficAttemptedToRecoverConnections / dataTime));
		output.append (String.format("<p>Number connections successfully recovered: %d (summing time average traffic: %f). </p>", stat_numSuccessfullyRecoveredConnections, stat_trafficSuccessfullyRecoveredConnections / dataTime));
		output.append (String.format("<p>Probability of successfully recover a connection: %f. Proability weighted by the connection traffic: %f). </p>", successProbabilityRecovery, successProbabilityTrafficRecovery));
//		output.append (String.format("<p>Total traffic carried at current state: %f. </p>", -1);
		return "";
	}

	@Override
	public void finishTransitory(double simTime)
	{
		this.stat_trafficOfferedConnections = 0;
		this.stat_trafficCarriedConnections = 0;
		this.stat_trafficAttemptedToRecoverConnections  = 0;
		this.stat_trafficSuccessfullyRecoveredConnections = 0;
		this.stat_numOfferedConnections = 0;
		this.stat_numCarriedConnections = 0;
		this.stat_numAttemptedToRecoverConnections = 0;
		this.stat_numSuccessfullyRecoveredConnections = 0;
		this.stat_transitoryInitTime = simTime;
	}

}
